﻿namespace NetFx.MSIL
{
  using System;
  using System.Text;
  using System.Threading;
  using System.Collections;

  using System.Reflection;
  using System.Reflection.Emit;

  using NetFx.SMIL;
  using NetFx.SMIL.Definitions;


  public interface TypeContainer
  {
    TypeGenerator DefineType(string name);
    TypeGenerator DefineType(string name, TypeAttributes attr, Type parent, PackingSize packSize);
    TypeGenerator DefineType(string name, TypeAttributes attr, Type parent, Type[] interfaces);
    TypeGenerator DefineType(string name, TypeAttributes attr);
    TypeGenerator DefineType(string name, TypeAttributes attr, Type parent);
    EnumGenerator DefineEnumeration(string name, TypeAttributes attributes, Type underlingType);
    IList Types { get; }
  }

  [Flags]
  public enum DefType
  {
    Any               =0x00000000,
    Assembly          =0x00000001,
    Module            =0x00000002,
    Member            =0x00000003,
    Type              =0x00000004,
    Enum              =0x00000005,
    Field             =0x00000006,
    Method            =0x00000007,
    Property          =0x00000008,
    Event             =0x00000009,
    Logic             =0x0000000A,
    Parameter         =0x0000000B,
    GenericParameter  =0x0000000C,
    Variable          =0x0000000D,
    Label             =0x0000000E,
    Labels            =0x0000000F,
  }

  public abstract class AnyGenerator:IDisposable
  {
    #region Fields
    protected bool isDisposed = false;
    protected bool isCommitted = false;
    protected ArrayList attributeList = new ArrayList();
    #endregion
    #region Properties
    public virtual bool IsCommitted
    {
      get
      {
        return this.isCommitted;
      }
    }
    public virtual bool IsDisposed
    {
      get
      {
        return this.isDisposed;
      }
    }
    public virtual DefType GeneratorType
    {
      get
      {
        return DefType.Any;
      }
    }
    public virtual object AnyBuilder
    {
      get
      {
        return null;
      }
    }
    #endregion
    #region Constructors
    public AnyGenerator()
    {

    }
    ~AnyGenerator()
    {
      this.Dispose();
    }
    #endregion
    #region Methods
    public virtual void Dispose()
    {
      this.Dispose(!this.IsDisposed);
    }
    protected virtual void Dispose(bool disposing)
    {
      if (disposing)
      {
        this.isDisposed = true;
        this.attributeList = null;
      }
    }
    protected virtual void DisposeCollection(bool disposing)
    {
      if (disposing)
      {
        this.attributeList.Clear();
      }
    }
    protected virtual void DisposeCollection(IList collection)
    {
      if (collection != null)
      {
        foreach (object o in collection)
        {
          if (o is IDisposable)
          {
            (o as IDisposable).Dispose();
          }
        }
        collection.Clear();
      }
    }
    public virtual void CommitGeneration()
    {
      this.isCommitted = true;
    }
    public virtual AnyGenerator Define(ReflectDef header)
    {
      if (header == null) throw new ArgumentNullException("header can not be null!");

      return header.Generate(this);
    }
    #region GenerateAttribute
    public virtual CustomAttributeBuilder CreateAttribute(ConstructorInfo con, object[] constructorArgs)
    {
      return this.SetCustomAttribute( new CustomAttributeBuilder(con, constructorArgs));
    }
    public virtual CustomAttributeBuilder CreateAttribute(
       ConstructorInfo con,
       object[] constructorArgs,
       FieldInfo[] namedFields,
       object[] fieldValues
    )
    {
      return this.SetCustomAttribute( new CustomAttributeBuilder(con, constructorArgs, namedFields, fieldValues));
    }
    public virtual CustomAttributeBuilder CreateAttribute(
       ConstructorInfo con,
       object[] constructorArgs,
       PropertyInfo[] namedProperties,
       object[] propertyValues
    )
    {
      return this.SetCustomAttribute(new CustomAttributeBuilder(con, constructorArgs, namedProperties, propertyValues));
    }

    public virtual CustomAttributeBuilder CreateAttribute(
       ConstructorInfo con,
       object[] constructorArgs,
       PropertyInfo[] namedProperties,
       object[] propertyValues,
       FieldInfo[] namedFields,
       object[] fieldValues
    )
    {
      return this.SetCustomAttribute( new CustomAttributeBuilder(con, constructorArgs, namedProperties, propertyValues, namedFields, fieldValues));
    }
    public virtual CustomAttributeBuilder SetCustomAttribute(CustomAttributeBuilder attribute)
    {
      this.attributeList.Add(attribute);
      return attribute;
    }
    #endregion
    #endregion
  }
}
